package com.xayy.health.mgt.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.Method;
import cn.kawins.base.result.CheckResult;
import cn.kawins.base.utils.BeanUtil;
import cn.kawins.base.utils.CollUtil;
import cn.kawins.base.utils.HttpUtil;
import cn.kawins.mybatis.base.BaseServiceImpl;
import cn.kawins.mybatis.util.SnowflakeId;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.xayy.health.core.config.param.ExternalParam;
import com.xayy.health.core.config.param.YcParam;
import com.xayy.health.core.constant.HealthManagerConstant;
import com.xayy.health.core.exception.HealthException;
import com.xayy.health.core.utils.TreeUtil;
import com.xayy.health.mgt.mapper.HealthAssessResultMapper;
import com.xayy.health.mgt.mapper.SatelliteNodeMapper;
import com.xayy.health.mgt.mapper.TelemetryDataMapper;
import com.xayy.health.mgt.model.*;
import com.xayy.health.mgt.model.dto.DataFeatureDto;
import com.xayy.health.mgt.model.dto.NodeDto;
import com.xayy.health.mgt.model.vo.SatelliteNodeTreeVo;
import com.xayy.health.mgt.model.vo.tupu.EquipmentResponseVo;
import com.xayy.health.mgt.model.vo.tupu.NodeVo;
import com.xayy.health.mgt.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @author zhangxa
 */
@Service
public class SatelliteNodeServiceImpl extends BaseServiceImpl<SatelliteNode> implements SatelliteNodeService {
    public static Map<Long,String>  nodeNameMap=null;
    @Autowired
    private SatelliteEdgeService satelliteEdgeService;
    @Autowired
    private SatelliteNodeMapper satelliteNodeMapper;
    @Autowired
    private TelemetryDataMapper telemetryDataMapper;
    @Autowired
    private YcParam ycParam;
    @Autowired
    DataQualityService dataQualityService;
    @Autowired
    private ExternalParam externalParam;
    @Autowired
    private HealthAssessResultService healthAssessResultService;

    @Autowired
    private FractionIntervalScoreService fractionIntervalScoreService;

    @Autowired
    private HealthAssessResultMapper healthAssessResultMapper;

    @Autowired
    private HealthAssessRecordService healthAssessRecordService;

    @Autowired
    private FaultInfoService faultInfoService;

    /**
     * 新增拓扑图节点
     *
     * @param satelliteNode 卫星节点信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(SatelliteNode satelliteNode) {
        Long id = new SnowflakeId().genId("tb_satellite_node", "id");
        satelliteNode.setId(id);
        if (satelliteNode.getPid() == null) {
            satelliteNode.setPid(id);
        } else {
            SatelliteEdge satelliteEdge = new SatelliteEdge();
            satelliteEdge.setNodeId(satelliteNode.getPid());
            satelliteEdge.setFrom(satelliteNode.getFrom());
            satelliteEdge.setTo(id);
            satelliteEdgeService.insert(satelliteEdge);
        }
        insert(satelliteNode);
    }

    /**
     * 获取卫星拓扑图节点(拓扑图)
     *
     * @param id 节点id
     * @return 拓扑节点信息
     */
    @Override
    public Map<String, Object> getList(Long id) {
        SatelliteNode satelliteNode = new SatelliteNode();
        satelliteNode.setPid(id);
        List<SatelliteNode> satelliteNodes = select(satelliteNode);
        satelliteNodes.stream().forEach((x) -> x.setLabel(x.getName()));
        SatelliteEdge satelliteEdge = new SatelliteEdge();
        satelliteEdge.setNodeId(id);
        List<SatelliteEdge> satelliteEdges = satelliteEdgeService.select(satelliteEdge);
        Map<String, Object> map = new HashMap<>(2);
        map.put("nodesArray", satelliteNodes);
        map.put("edgesArray", satelliteEdges);
        return map;
    }

    /**
     * 获取卫星拓扑图节点(分页)
     *
     * @param nodeDto 节点信息
     * @return 分页信息
     */
    @Override
    public PageInfo<SatelliteNode> pageList(NodeDto nodeDto) {
        PageMethod.startPage(nodeDto.getPage(), nodeDto.getSize());
        SatelliteNode satelliteNode = new SatelliteNode();
        satelliteNode.setSatelliteId(nodeDto.getSatelliteId());
        List<SatelliteNode> satelliteNodes = satelliteNodeMapper.getList(satelliteNode);
        return new PageInfo<>(satelliteNodes);
    }

    /**
     * 查询卫星节点信息集合
     *
     * @param id id信息
     * @return 结果日志
     */
    @Override
    public List<SatelliteNodeTreeVo> getSatelliteNodeList(Long id) {
        return satelliteNodeMapper.getSatelliteNodeList(id);
    }

    /**
     * 判断节点是否有子节点
     *
     * @param id id信息
     * @return 结果日志
     */
    @Override
    public boolean hasEdge(Long id) {
        int result = satelliteNodeMapper.hasEdge(id);
        return result > 0;
    }

    /**
     * 健康评估根据卫星id获取树结构
     *
     * @param id 卫星id
     * @return 结果日志
     */
    @Override
    public SatelliteNodeTreeVo getDefRootId(Long id) {
        SatelliteNodeTreeVo satelliteNodeTreeVo = new SatelliteNodeTreeVo();
        SatelliteNode node = selectById(id);
        List<SatelliteNodeTreeVo> satelliteNodeList = getSatelliteNodeList(id);
        satelliteNodeTreeVo.setNodeId(id);
        satelliteNodeTreeVo.setNodeName(node.getName());
        satelliteNodeTreeVo.setPid(0L);
        satelliteNodeTreeVo.setId(id);
        satelliteNodeTreeVo.setName(node.getName());
        List<SatelliteNodeTreeVo> children = cn.kawins.base.utils.TreeUtil.toTree(id, satelliteNodeList);
        satelliteNodeTreeVo.setChildren(children);
        List<SatelliteNodeTreeVo> list = TreeUtil.toList(ListUtil.toList(satelliteNodeTreeVo));
        List<SatelliteNodeTreeVo> tree = cn.kawins.base.utils.TreeUtil.toTree(0L, list);
        return tree.get(0);
    }

    /**
     * 健康评估获取树结构(外部接口)
     *
     * @param node 卫星节点信息
     * @return 结果日志
     */
    @Override
    public SatelliteNodeTreeVo getDefRoot(SatelliteNode node) {
        return getDefRootFullTree(node).getData();
    }

    /**
     * 获取树型数据
     *
     * @param node node信息
     * @return CheckResult<SatelliteNodeTreeVo>
     */
    public CheckResult<SatelliteNodeTreeVo> getDefRootFullTree(SatelliteNode node) {
        List<HealthAssessResult> resList=new ArrayList<>();
        List<SatelliteNodeTreeVo> satelliteNodeList = getTreeList(node);
        List<SatelliteNodeTreeVo> tree = cn.kawins.base.utils.TreeUtil.toTree(0L, satelliteNodeList);
        //插入默认权重数据
        setDefaultWeightData(node, tree, resList);
        //更新故障信息
        faultInfoService.leadFaultInfos();
        return CheckResult.success(tree.get(0));
    }

    /**
     * 插入默认权重数据
     * @param node  node信息
     * @param tree 树状图
     * @param resList 结果
     */
    private void setDefaultWeightData(SatelliteNode node, List<SatelliteNodeTreeVo> tree, List<HealthAssessResult> resList) {
        SatelliteNodeTreeVo satelliteNodeTreeVo = tree.get(0);
        if (null != satelliteNodeTreeVo && 1 == satelliteNodeTreeVo.getLevel()) {
            List<SatelliteNodeTreeVo> level2List = satelliteNodeTreeVo.getChildren();
            if (!CollectionUtils.isEmpty(level2List)) {
                //一级
                boolean flag = setNodeScore(satelliteNodeTreeVo.getNodeId(), node.getName(), satelliteNodeTreeVo.getId(), satelliteNodeTreeVo.getPid(), 0D, 1, resList);
                if (flag) {
                    //二级
                    int level2Size = level2List.size();
                    BigDecimal l2Aver = getAVerNum(level2Size);
                    for (int i = 0; i < level2List.size(); i++) {
                        SatelliteNodeTreeVo level2Vo = level2List.get(i);
                        if (2 == level2Vo.getLevel()) {
                            if (i == level2List.size() - 1) {
                                l2Aver = BigDecimal.ONE.subtract(l2Aver.multiply(new BigDecimal(level2List.size() - 1)));
                            }
                            setNodeScore(level2Vo.getNodeId(), node.getName(), level2Vo.getId(), level2Vo.getPid(), l2Aver.doubleValue(), 2, resList);
                            List<SatelliteNodeTreeVo> level3List = level2Vo.getChildren();
                            if (!CollectionUtils.isEmpty(level3List)) {
                                //三级
                                BigDecimal l3Aver = getAVerNum(level3List.size());
                                for (int j = 0; j < level3List.size(); j++) {
                                    SatelliteNodeTreeVo level3Vo = level3List.get(j);
                                    if (3 == level3Vo.getLevel()) {
                                        if (j == level3List.size() - 1) {
                                            l3Aver = BigDecimal.ONE.subtract(l3Aver.multiply(new BigDecimal(level3List.size() - 1)));
                                        }
                                        setNodeScore(level3Vo.getNodeId(), node.getName(), level3Vo.getId(), level3Vo.getPid(), l3Aver.doubleValue(), 3, resList);
                                    }

                                }

                            }
                        }
                    }
                }
            }
        }
        if(!CollectionUtils.isEmpty(resList)){
            healthAssessResultMapper.insertList(resList);
        }
    }

    /**
     * 设置分数平均值
     * @param satelliteMid satelliteMid
     * @param satelliteName satelliteName
     * @param nodeMid nodeMid
     * @param parentId parentId
     * @return 是否是首次插入数据
     */
    public boolean setNodeScore(Long satelliteMid, String satelliteName, Long nodeMid, Long parentId,Double weight,int level, List<HealthAssessResult> resList) {
        HealthAssessResult assessResult =
                HealthAssessResult.builder().parentId(parentId).nodeMid(nodeMid).satelliteMid(satelliteMid).build();
        HealthAssessResult result = healthAssessResultMapper.selectOne(assessResult);
        if (Objects.isNull(result)) {
            result = new HealthAssessResult();
            result.setIsComponent(1 != level);
            result.setParentId(parentId);
            result.setNodeMid(nodeMid);
            result.setSatelliteMid(satelliteMid);
            result.setSatelliteName(satelliteName);
            result.setFaultFraction(95);
            result.setNatureFraction(95);
            result.setMultipleFraction(95);
            result.setSatisfaction("健康");
            result.setFractionTime(new Date());
            result.setFaultWeight(80D);
            result.setScoringRule(2);
            result.setFaultFactionIntroduction("手动故障评分为95分。");
            result.setNatureFactionIntroduction("手动性能评分为95分。");
            result.setEvaluatingWeight(weight);
            resList.add(result);
//            healthAssessResultMapper.insertSelective(result);
//            HealthAssessRecord healthAssessRecord =
//                    HealthAssessResultServiceImpl.buildRecord(result, String.valueOf(result.getSatelliteName()), result.getNodeName());
//            healthAssessRecordService.insert(healthAssessRecord);
            return true;
        }
        return false;
    }


    /**
     * 获取平均值
     *
     * @param size 数量
     * @return 平均值
     */
    public BigDecimal getAVerNum(int size) {
        return BigDecimal.ONE.divide(new BigDecimal(size), 6, RoundingMode.DOWN);
    }

    /**
     * 获取遥测信息
     *
     * @param dataFeatureDto 入参信息
     * @return 结果日志
     */
    @Override
    public List<TelemetryData> getYcList(DataFeatureDto dataFeatureDto) {
        if (Boolean.TRUE.equals(ycParam.getYcApiOrDb())) {
            return getYcListByApi(dataFeatureDto);
        } else {
            List<TelemetryData> ycList = telemetryDataMapper.getYcList(dataFeatureDto);
            if (!CollectionUtils.isEmpty(ycList)) {
                for (TelemetryData telemetryData : ycList) {
                    if (StringUtils.isEmpty(telemetryData.getValue())) {
                        telemetryData.setValue(null);
                    }
                }
            }
            return ycList;
        }
    }

    /**
     * 获取树节点信息
     *
     * @param node 节点信息
     * @return 结果日志
     */
    @Override
    public List<SatelliteNodeTreeVo> getTreeList(SatelliteNode node) {
        nodeNameMap=new HashMap<>();
        SatelliteNodeTreeVo satelliteNodeTreeVo = new SatelliteNodeTreeVo();

        List<SatelliteNodeTreeVo> satelliteNodeList = new ArrayList<>();
        // 获取分系统层
        Map<String, Object> map = new HashMap<>(3);
        map.put("filterFlag", true);
        map.put("id", node.getId());
        map.put("labelName", "星");
        HttpResponse getResponse = HttpUtil.createRequest(Method.GET, externalParam.satSysUrl).form(map).execute();
        if (getResponse.getStatus() != HttpStatus.HTTP_OK) {
            log.error("调用星-分系统信息获取接口异常");
        }
        Object data = JSON.parseObject(getResponse.body()).get("data");
        if (BeanUtil.isEmpty(data)) {
            return CollUtil.newArrayList();
        }
        EquipmentResponseVo tupu = JSON.parseObject(data.toString(), EquipmentResponseVo.class);
        List<NodeVo> nodes = tupu.getNodes();
        Long satId = node.getId();
        String satName = node.getXing();
        Map<String, Object> colorMap = distinguishSateliteColor(satId, satId);
        satelliteNodeTreeVo.setNodeId(satId);
        satelliteNodeTreeVo.setNodeName(satName);
        satelliteNodeTreeVo.setPid(0L);
        satelliteNodeTreeVo.setId(satId);
        satelliteNodeTreeVo.setFromName(satName);
        satelliteNodeTreeVo.setName(satName);
        satelliteNodeTreeVo.setLevel(1);
        satelliteNodeTreeVo.setItemStyle(colorMap);
        satelliteNodeList.add(satelliteNodeTreeVo);
        nodes.forEach(x -> {
            if (HealthManagerConstant.XING.equals(x.getLabel()) || BeanUtil.isEmpty(x.getId())) {
                return;
            }
            SatelliteNodeTreeVo satelliteNodeTreeVo1 = new SatelliteNodeTreeVo();
            Long nodeId = Convert.toLong(x.getId());
            Map<String, Object> colorMap1 = distinguishSateliteColor(satId, nodeId);
            String nodeName = Convert.toStr(x.getProperties().getName());
            satelliteNodeTreeVo1.setNodeId(satId);
            satelliteNodeTreeVo1.setNodeName(satName);
            satelliteNodeTreeVo1.setPid(satId);
            satelliteNodeTreeVo1.setId(nodeId);
            satelliteNodeTreeVo1.setFromName(satName);
            satelliteNodeTreeVo1.setName(nodeName);
            satelliteNodeTreeVo1.setItemStyle(colorMap1);
            satelliteNodeTreeVo1.setLevel(2);
            satelliteNodeList.add(satelliteNodeTreeVo1);
            nodeNameMap.put(nodeId,nodeName);
            // 查询分系统下的部件
            CheckResult<List<SatelliteNodeTreeVo>> component = getComponent(satelliteNodeTreeVo1);
            satelliteNodeList.addAll(component.getData());
        });
        return satelliteNodeList;
    }

    /**
     * 获取部件
     *
     * @param node node信息
     * @return CheckResult<List < SatelliteNodeTreeVo>>
     */
    public CheckResult<List<SatelliteNodeTreeVo>> getComponent(SatelliteNodeTreeVo node) {
        List<SatelliteNodeTreeVo> components = new ArrayList<>();

        // 获取部件层
        Map<String, Object> map = new HashMap<>(3);
        map.put("filterFlag", true);
        map.put("id", node.getId());
        map.put("labelName", "分系统");
        HttpResponse getResponse = HttpUtil.createRequest(Method.GET, externalParam.sysComUrl).form(map).execute();
        if (getResponse.getStatus() != HttpStatus.HTTP_OK) {
            log.error("调用分系统-部件信息获取接口异常");
            return CheckResult.fail("调用分系统-部件信息获取接口异常");
        }
        Object data = JSON.parseObject(getResponse.body()).get("data");
        if (BeanUtil.isEmpty(data)) {
            return CheckResult.success(CollUtil.newArrayList());
        }
        EquipmentResponseVo responseVo = JSON.parseObject(data.toString(), EquipmentResponseVo.class);
        List<NodeVo> nodes = responseVo.getNodes();


        nodes.forEach(x -> {
            if (HealthManagerConstant.COMPONENT.equals(x.getLabel()) || BeanUtil.isEmpty(x.getId())) {
                return;
            }
            SatelliteNodeTreeVo satelliteNodeTreeVo = new SatelliteNodeTreeVo();
            Long nodeId = Convert.toLong(x.getId());
            String nodeName = Convert.toStr(x.getProperties().getName());
            satelliteNodeTreeVo.setNodeId(node.getNodeId());
            Map<String, Object> stringObjectMap = distinguishSateliteColor(node.getNodeId(), nodeId);
            satelliteNodeTreeVo.setItemStyle(stringObjectMap);
            satelliteNodeTreeVo.setNodeName(node.getNodeName());
            satelliteNodeTreeVo.setPid(node.getId());
            satelliteNodeTreeVo.setId(nodeId);
            satelliteNodeTreeVo.setFromName(node.getName());
            satelliteNodeTreeVo.setName(nodeName);
            satelliteNodeTreeVo.setLevel(3);
            nodeNameMap.put(nodeId,nodeName);
            components.add(satelliteNodeTreeVo);

        });
        return CheckResult.success(components);
    }


    /**
     * 区分卫星颜色
     *
     * @param satId  卫星id
     * @param nodeId 节点id
     * @return Map<String, Object>
     */
    public Map<String, Object> distinguishSateliteColor(Long satId, Long nodeId) {
        HashMap<String, Object> colorMap = new HashMap<>(2);
        Example example = new Example(HealthAssessResult.class);
        example.createCriteria().andEqualTo("satelliteMid", satId).andEqualTo("nodeMid", nodeId);
        List<HealthAssessResult> assessResults = null;
        if (satId.equals(nodeId)) {
            assessResults = healthAssessResultService.selectByExample(example);
        } else if (nodeId.toString().length() == 1) {
            assessResults = healthAssessResultService.selectByExample(example);
        } else if (nodeId.toString().length() > 1) {
            assessResults = healthAssessResultService.selectByExample(example);
        }
        Example exampleScore = new Example(FractionIntervalScore.class);
        exampleScore.createCriteria().andEqualTo("fractionType", 2);
        List<FractionIntervalScore> scoreList = fractionIntervalScoreService.selectByExample(exampleScore);

        for (HealthAssessResult health : assessResults) {
            String satisfaction = health.getSatisfaction();
            for (FractionIntervalScore score : scoreList) {
                if (score.getFractionName().equals(satisfaction)) {
                    colorMap.put("color", score.getColor());
                }
            }
        }
        return colorMap;
    }

    /**
     * 从api获取遥测数据
     *
     * @param dataFeatureDto 入参
     * @return List<TelemetryData>
     */
    private List<TelemetryData> getYcListByApi(DataFeatureDto dataFeatureDto) {
        JSONObject parms = new JSONObject();
        if (dataFeatureDto.getStartTime() != null) {
            long startTimeStamp = dataFeatureDto.getStartTime().getTime();
            parms.put("timeStart", startTimeStamp);
        }
        if (dataFeatureDto.getEndTime() != null) {
            long endTimeStamp = dataFeatureDto.getEndTime().getTime();
            parms.put("timeEnd", endTimeStamp);
        }
        parms.put("param", new ArrayList<>());
        List<String> column = new ArrayList<>();
        column.add("time");
        column.add(dataFeatureDto.getParamCode());
        parms.put("column", column);
        parms.put("timeField", "time");
        Integer timeInterval = dataFeatureDto.getTimeInterval();
        if (timeInterval != null && timeInterval.compareTo(0) > 0) {
            parms.put("jumpPoint", timeInterval+"s");
            column.remove(1);
            column.add(dataFeatureDto.getParamCode());
        }
        parms.put("businessKey", dataFeatureDto.getSatelliteCode());
        log.info("****************************调用遥测入参****************************");
        log.info(parms.toString());
        log.info("********************************************************");
        // 1通信2中继
        List<TelemetryData> ycList = new ArrayList<>();
        log.info("****************************开始遥测调用****************************");
        HttpResponse getResponse = HttpUtil.createRequest(Method.POST, ycParam.getYcApi()).body(parms.toString()).timeout(600000).execute();
        if (getResponse.getStatus() != HttpStatus.HTTP_OK) {
            throw new RuntimeException("调用查询遥测接口异常");
        }
        log.info("****************************遥测调用完成****************************");
        JSONArray ycVos = JSON.parseObject(getResponse.body()).getJSONArray("data");
        long timeFormatStart = System.currentTimeMillis();
        log.info("遥测时间格式处理开始时间：" + timeFormatStart);

        //判断遥测数据是否全部为空
        if (CollUtil.isNotEmpty(ycVos)) {
            ycVos.forEach(ycData -> {
                JSONObject item = JSONObject.parseObject(JSON.toJSONString(ycData), JSONObject.class);

                String time = item.getString("time");
                String value = item.getString(dataFeatureDto.getParamCode());

                TelemetryData telemetryData = new TelemetryData();
                telemetryData.setSateCode(dataFeatureDto.getSatelliteCode());
                telemetryData.setParamCode(dataFeatureDto.getParamCode());
                //log.info("遥测时间原始格式：" + time);
                if (time.length() > HealthManagerConstant.TIME_TWENTY_THREE) {
                    String millsTime = time.substring(0, 23);
                    String timeStr = millsTime.replace("T", " ");
                    telemetryData.setTime(timeStr);
                    //log.info("遥测时间处理之后的格式：" + timeStr);
                } else {
                    telemetryData.setTime(time);
                }
                if(StringUtils.isEmpty(value)){
                    value = null;
                }
                telemetryData.setValue(value);
                ycList.add(telemetryData);
            });
        } else {
            //TODO: 业务处理信息应返回正常的对象,而不是抛出异常
            throw new HealthException("参数" + dataFeatureDto.getParamCode() + "遥测数据为空");
        }
        long timeFormatEnd = System.currentTimeMillis();
        log.info("遥测时间格式处理完成时间：" + timeFormatEnd);
        log.info("遥测时间格式处理总耗时={}",timeFormatEnd-timeFormatStart);
        return ycList;
    }


    /**
     * 故障评分规则表
     */
    @Override
    public List<HealthAssessResult> getHealthRuleTable(SatelliteNode node){
        Example example=new Example(HealthAssessResult.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("satelliteName",node.getName());
        if(StringUtils.isEmpty(node.getPid())){
            node.setPid(0L);
        }
        criteria.andNotEqualTo("parentId",node.getPid());
        example.orderBy("nodeMid");
        List<HealthAssessResult> healthAssessResultList=healthAssessResultMapper.selectByExample(example);
        if(!CollectionUtils.isEmpty(healthAssessResultList)&&!CollectionUtils.isEmpty(nodeNameMap)){
             for(HealthAssessResult healthAssessResult:healthAssessResultList){
                 Long id=healthAssessResult.getNodeMid();
                 healthAssessResult.setNodeName(nodeNameMap.get(id));
             }
        }
         return healthAssessResultList;
    }
}
